home *** CD-ROM | disk | FTP | other *** search
/ Gigarom 4 / Mac Giga-ROM 4.0 - 1993.toast / FILES / EXT / A-E / basicblack1.0.cpt / Basic Black / Basic Black.c next >
C/C++ Source or Header  |  1993-03-27  |  13KB  |  425 lines

  1. /**********************************************************
  2.  * Basic Black © 1993 by Mason L. Bliss
  3.  * 
  4.  * This is a minimal screen saver. All it does (though it
  5.  * can be easily extended) is black out the screen after a
  6.  * specified time. It lets background (and foreground, for
  7.  * that matter) tasks run at full speed, as it doesn't waste
  8.  * any time on whizbang graphics. (Hence the name...)
  9.  *
  10.  * The trap patching code is taken from a neat little program
  11.  * Mike Scanlin wrote for the August '92 MacTutor.
  12.  *
  13.  * Basic Black's screen-blanking routine is based on a routine
  14.  * by Christopher Tate.
  15.  *
  16.  * It also makes use of CShowInit, by Ken McLeod, to put
  17.  * up its icon at startup time.
  18.  **********************************************************/
  19.  
  20.  
  21.  
  22. #include "Traps.h"
  23. #define    ON    1
  24. #define    OFF    0
  25. #define    SLEEPTICKS            7200    /* 7200 ticks = 2 minutes */
  26. #define INSTANTSLEEPTICKS    45        /* 1 minute = 3600 ticks */
  27.  
  28.  
  29.  
  30. /**********************************************************
  31.  * typedefs
  32.  **********************************************************/
  33.  
  34. typedef pascal short (*WNEProcPtr) (short eventMask, EventRecord *theEvent, long sleep, RgnHandle mouseRgn);
  35. typedef pascal short (*GNEProcPtr) (short eventMask, EventRecord *theEvent);
  36. typedef pascal short (*SEProcPtr) (EventRecord *theEvent);
  37. typedef pascal short (*STProcPtr) (void);
  38. typedef struct {
  39.         char    privates[76];
  40.         long    randSeed;
  41.         BitMap  screenBits;
  42.         Cursor  arrow;
  43.         Pattern dkGray;
  44.         Pattern ltGray;
  45.         Pattern black;
  46.         Pattern white;
  47.         GrafPtr thePort;
  48.         long    qdend;
  49. } QDGlobals;
  50.  
  51. typedef struct PatchGlobals {
  52.     WNEProcPtr        pgOldWNE;
  53.     GNEProcPtr        pgOldGNE;
  54.     SEProcPtr        pgOldSE;
  55.     STProcPtr        pgOldST;
  56.     short            pgSleepState,
  57.                     pgGonnaFallAsleep,
  58.                     pgOldMBarHeight;
  59.     long            pgLastAction;
  60.     Point            pgLastMouse;
  61.     Rect            pgSleepRect,
  62.                     pgWakeRect;
  63.     GrafPort        pgMyPort;
  64.     GrafPtr            pgOldPort;
  65.     RgnHandle        pgOldGrayRgn,
  66.                     pgNullRgn;
  67.     WindowPtr        pgFrontWin;
  68. } PatchGlobals, *PatchGlobalsPtr;
  69.  
  70.  
  71.  
  72. /**********************************************************
  73.  * prototypes
  74.  **********************************************************/
  75.  
  76. void main(void);
  77. void StartPatchCode(void);
  78. pascal short MyWaitNextEvent(short eventMask, EventRecord *theEvent, long sleep, RgnHandle mouseRgn);
  79. pascal short MyGetNextEvent(short eventMask, EventRecord *theEvent);
  80. pascal short MySystemEvent(EventRecord *theEvent);
  81. void MySystemTask(void);
  82. void FallAsleep(void);
  83. void WakeUp(void);
  84. void EndPatchCode(void);
  85.  
  86.  
  87.  
  88. /**********************************************************
  89.  * main:
  90.  * Gets memory in the system heap, and installs the WNE, GNE,
  91.  * and SE patches (as well as allocating and initializing
  92.  * the patch globals). This is the only routine that gets
  93.  * executed at startup time (by the INIT mechanism).
  94.  *
  95.  * The block of memory that main allocates will look like
  96.  * this when main has finished:
  97.  *
  98.  *                     +--------------------+
  99.  *                     |      PatchGlobals      |
  100.  *                     +--------------------+
  101.  *                     |  StartPatchCode()  |
  102.  *    WNE trap addr -> +--------------------+
  103.  *                     |  MyWaitNextEvent() |
  104.  *    GNE trap addr -> +--------------------+
  105.  *                     |  MyGetNextEvent()  |
  106.  *     SE trap addr -> +--------------------+
  107.  *                     |  MySystemEvent()   |
  108.  *     ST trap addr -> +--------------------+
  109.  *                     |  MySystemTask()    |
  110.  *                     +--------------------+
  111.  *                     |  CheckKeyCase()    |
  112.  *                     +--------------------+
  113.  *                     |  EndPatchCode()    |
  114.  *                     +--------------------+
  115.  *
  116.  **********************************************************/
  117. void main()
  118. {
  119.     Ptr                patchPtr;
  120.     PatchGlobalsPtr    pgPtr;
  121.     long            codeSize, offset, oldA5;
  122.     QDGlobals        qd;
  123.     GrafPort        gp;
  124.     
  125.     /* try and get some memory in the system heap for code and globals */
  126.     codeSize = (long) EndPatchCode - (long) StartPatchCode;
  127.     patchPtr = NewPtrSys(codeSize + sizeof(PatchGlobals));
  128.     if (!patchPtr)
  129.         return;    /* out of memory -- abort patching */
  130.     
  131.     // initialize the patch globals at the beginning of the block
  132.     pgPtr = (PatchGlobalsPtr) patchPtr;
  133.     pgPtr->pgOldWNE = (WNEProcPtr) GetTrapAddress(_WaitNextEvent);
  134.     pgPtr->pgOldGNE = (GNEProcPtr) GetTrapAddress(_GetNextEvent);
  135.     pgPtr->pgOldSE = (SEProcPtr) GetTrapAddress(_SystemEvent);
  136.     pgPtr->pgOldST = (STProcPtr) GetTrapAddress(_SystemTask);
  137.     pgPtr->pgSleepState = OFF;
  138.     pgPtr->pgGonnaFallAsleep = OFF;
  139.     pgPtr->pgLastAction = Ticks;
  140.     pgPtr->pgNullRgn = 0L;
  141.     
  142.     // This next bit of stuff fakes out some QuickDraw globals to get the
  143.     // correct sleep and wake rectangles.
  144.     oldA5 = SetA5((long) &qd.qdend);    // Tell A5 to point to our 'fake' QD Globals
  145.     InitGraf(&qd.thePort);                // Initialize our QD Globals
  146.     OpenPort((GrafPtr) &gp);
  147.     (pgPtr->pgSleepRect).left = (gp.portRect).right - 5;    // Set sleep rect
  148.     (pgPtr->pgSleepRect).right = (gp.portRect).right + 1;
  149.     (pgPtr->pgSleepRect).top = (gp.portRect).top - 1;
  150.     (pgPtr->pgSleepRect).bottom = (gp.portRect).top + 5;
  151.  
  152.     (pgPtr->pgWakeRect).left = (gp.portRect).right - 5;        // Set wake rect
  153.     (pgPtr->pgWakeRect).right = (gp.portRect).right + 1;
  154.     (pgPtr->pgWakeRect).top = (gp.portRect).bottom - 5;
  155.     (pgPtr->pgWakeRect).bottom = (gp.portRect).bottom + 1;
  156.     ClosePort((GrafPtr) &gp);
  157.     oldA5 = SetA5(oldA5);                // Restore A5 to its previous value
  158.  
  159.     GetMouse(&(pgPtr->pgLastMouse));
  160.     LocalToGlobal(&(pgPtr->pgLastMouse));
  161.  
  162.  
  163.     /* move the code into place after the globals */
  164.     BlockMove(StartPatchCode, patchPtr + sizeof(PatchGlobals), codeSize);
  165.     
  166.     /* set the patches */
  167.     patchPtr += sizeof(PatchGlobals);
  168.     offset = (long) MyWaitNextEvent - (long) StartPatchCode;
  169.     SetTrapAddress((long) patchPtr + offset, _WaitNextEvent);
  170.     offset = (long) MyGetNextEvent - (long) StartPatchCode;
  171.     SetTrapAddress((long) patchPtr + offset, _GetNextEvent);
  172.     offset = (long) MySystemEvent - (long) StartPatchCode;
  173.     SetTrapAddress((long) patchPtr + offset, _SystemEvent);
  174.     offset = (long) MySystemTask - (long) StartPatchCode;
  175.     SetTrapAddress((long) patchPtr + offset, _SystemTask);
  176. }
  177.  
  178.  
  179.  
  180. /**********************************************************
  181.  * StartPatchCode:
  182.  * Dummy proc to mark the beginning of the code for the
  183.  * patches. Make sure all of your patch code is between
  184.  * here and EndPatchCode.
  185.  **********************************************************/
  186. void StartPatchCode()
  187. {
  188. }
  189.  
  190.  
  191.  
  192. /**********************************************************
  193.  * MyWaitNextEvent:
  194.  * Tail patch on WaitNextEvent.
  195.  *
  196.  * The reason this returns a short instead of a Boolean is
  197.  * because we need to make sure the low byte of the top word
  198.  * on the stack is zero because some programs do a Tst.W
  199.  * (SP)+ when this returns instead of Tst.B (SP)+ like they
  200.  * should (which is technically their bug but, we might as
  201.  * well work around it since it's not hard).
  202.  *
  203.  * If you want to eat the event and not pass it on to the
  204.  * caller then set returnValue to zero.
  205.  **********************************************************/
  206. pascal short MyWaitNextEvent(short eventMask, EventRecord *theEvent, long sleep, RgnHandle mouseRgn)
  207. {
  208.     PatchGlobalsPtr    pgPtr;
  209.     short            returnValue;
  210.     register short    foo;
  211.     
  212.     /* find our globals */
  213.     pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
  214.     
  215.     /* call original GNE first */
  216.     returnValue = (*pgPtr->pgOldWNE) (eventMask, theEvent, sleep, mouseRgn);
  217.     
  218.     if ((foo = theEvent->what) >= 1 && foo <= 5 || foo == 7) {
  219.         pgPtr->pgLastAction = Ticks;    /* Update last time counter */
  220.         pgPtr->pgGonnaFallAsleep = OFF;
  221.         if (pgPtr->pgSleepState)
  222.             WakeUp();
  223.     }
  224.     
  225.     /* return to original caller */
  226.     return (returnValue);
  227. }
  228.  
  229.  
  230.  
  231. /**********************************************************
  232.  * MyGetNextEvent:
  233.  * Tail patch on GetNextEvent.
  234.  *
  235.  * The reason this returns a short instead of a Boolean is
  236.  * because we need to make sure the low byte of the top word
  237.  * on the stack is zero because some programs do a Tst.W
  238.  * (SP)+ when this returns instead of Tst.B (SP)+ like they
  239.  * should (which is technically their bug but, we might as
  240.  * well work around it since it's not hard).
  241.  *
  242.  * If you want to eat the event and not pass it on to the
  243.  * caller then set returnValue to zero.
  244.  **********************************************************/
  245. pascal short MyGetNextEvent(short eventMask, EventRecord *theEvent)
  246. {
  247.     PatchGlobalsPtr    pgPtr;
  248.     short            returnValue;
  249.     register short    foo;
  250.     
  251.     /* find our globals */
  252.     pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
  253.     
  254.     /* call original GNE first */
  255.     returnValue = (*pgPtr->pgOldGNE) (eventMask, theEvent);
  256.     
  257.     if ((foo = theEvent->what) >= 1 && foo <= 5 || foo == 7) {
  258.         pgPtr->pgLastAction = Ticks;    /* Update last time counter */
  259.         pgPtr->pgGonnaFallAsleep = OFF;
  260.         if (pgPtr->pgSleepState)
  261.             WakeUp();
  262.     }
  263.     
  264.     /* return to original caller */
  265.     return (returnValue);
  266. }
  267.  
  268.  
  269.  
  270. /**********************************************************
  271.  * MySystemEvent:
  272.  * Tail patch on SystemEvent.
  273.  *
  274.  * The reason this returns a short instead of a Boolean is
  275.  * because we need to make sure the low byte of the top word
  276.  * on the stack is zero because some programs do a Tst.W
  277.  * (SP)+ when this returns instead of Tst.B (SP)+ like they
  278.  * should (which is technically their bug but, we might as
  279.  * well work around it since it's not hard).
  280.  *
  281.  * We need this patch as well as the one on GetNextEvent
  282.  * because of desk accessories. If you don't patch
  283.  * SystemEvent then the patch will not apply to events that
  284.  * are sent to DAs.
  285.  *
  286.  * If you want to eat the event and not pass it on to the
  287.  * caller then set returnValue to zero.
  288.  **********************************************************/
  289. pascal short MySystemEvent(EventRecord *theEvent)
  290. {
  291.     PatchGlobalsPtr    pgPtr;
  292.     short            returnValue;
  293.     register short    foo;
  294.     
  295.     /* find our globals */
  296.     pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
  297.     
  298.     /* call original SE first */
  299.     returnValue = (*pgPtr->pgOldSE) (theEvent);
  300.     
  301.     if ((foo = theEvent->what) >= 1 && foo <= 5 || foo == 7) {
  302.         pgPtr->pgLastAction = Ticks;    /* Update last time counter */
  303.         pgPtr->pgGonnaFallAsleep = OFF;
  304.         if (pgPtr->pgSleepState)
  305.             WakeUp();
  306.     }
  307.     
  308.     /* return to original caller */
  309.     return (returnValue);
  310. }
  311.  
  312.  
  313.  
  314. /**********************************************************
  315.  * MySystemTask:
  316.  * Tail patch on SystemTask.
  317.  *
  318.  * This is where most of the stuff's done.
  319.  **********************************************************/
  320. void MySystemTask(void)
  321. {
  322.     PatchGlobalsPtr    pgPtr;
  323.     Point            mousePt;
  324.     
  325.     /* find our globals */
  326.     pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
  327.     
  328.     /* call original ST first */
  329.     (*pgPtr->pgOldST) ();
  330.     
  331.     GetMouse(&mousePt);
  332.     LocalToGlobal(&mousePt);
  333.     if (!EqualPt(mousePt, pgPtr->pgLastMouse)) {    /* Mouse moved */
  334.         pgPtr->pgLastMouse = mousePt;
  335.         pgPtr->pgLastAction = Ticks;
  336.         pgPtr->pgGonnaFallAsleep = OFF;
  337.         if (pgPtr->pgSleepState)
  338.             WakeUp();
  339.     }
  340.     if (!(pgPtr->pgGonnaFallAsleep) && PtInRect(mousePt, &pgPtr->pgSleepRect)) {
  341.         pgPtr->pgGonnaFallAsleep = ON;
  342.         pgPtr->pgLastAction -= (SLEEPTICKS - INSTANTSLEEPTICKS);
  343.     }
  344.     if (PtInRect(mousePt, &pgPtr->pgWakeRect))
  345.         pgPtr->pgLastAction = Ticks;
  346.     if (((Ticks - (pgPtr->pgLastAction)) > SLEEPTICKS) && !(pgPtr->pgSleepState))
  347.         FallAsleep();
  348. }
  349.  
  350.  
  351.  
  352. /**********************************************************
  353.  * FallAsleep:
  354.  *
  355.  * This is where we black out the screen.
  356.  **********************************************************/
  357. void FallAsleep(void)
  358. {
  359.     PatchGlobalsPtr    pgPtr;
  360.     
  361.     /* find our globals */
  362.     pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
  363.     
  364.     /* Kill off the menu bar and cursor, and get ready for bed */
  365.     pgPtr->pgSleepState = ON;
  366.     pgPtr->pgOldMBarHeight = MBarHeight;
  367.     MBarHeight = 0;
  368.     HideCursor();
  369.     
  370.     /* Here's where it happens */
  371.     GetPort(&(pgPtr->pgOldPort));    /* Get the old port */
  372.     OpenPort(&(pgPtr->pgMyPort));
  373.     pgPtr->pgOldGrayRgn = GrayRgn;
  374.     GrayRgn = pgPtr->pgNullRgn;
  375.     PaintRect(&(pgPtr->pgMyPort.portRect));
  376.     
  377.     /* No man may draw here. */
  378.     CalcVisBehind((WindowPeek) FrontWindow(), pgPtr->pgOldGrayRgn);
  379.     SetPort(pgPtr->pgOldPort);    /* Set up the old port */
  380. }
  381.  
  382.  
  383.  
  384. /**********************************************************
  385.  * WakeUp:
  386.  *
  387.  * This is where we force a redraw and give things access
  388.  * to the screen again.
  389.  **********************************************************/
  390. void WakeUp(void)
  391. {
  392.     PatchGlobalsPtr    pgPtr;
  393.     
  394.     /* find our globals */
  395.     pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
  396.     
  397.     pgPtr->pgSleepState = OFF;
  398.     pgPtr->pgGonnaFallAsleep = OFF;
  399.     pgPtr->pgLastAction = Ticks;
  400.     MBarHeight = pgPtr->pgOldMBarHeight;
  401.     
  402.     /* This next block is Chris' code */
  403.     GetPort(&(pgPtr->pgOldPort));
  404.     SetPort(&(pgPtr->pgMyPort));
  405.     GrayRgn = pgPtr->pgOldGrayRgn;
  406.     pgPtr->pgFrontWin = FrontWindow();
  407.     PaintBehind((WindowPeek) pgPtr->pgFrontWin, GrayRgn);
  408.     CalcVisBehind((WindowPeek) pgPtr->pgFrontWin, GrayRgn);    /* force redraw */
  409.     DrawMenuBar();
  410.     ShowCursor();
  411.     ClosePort(&(pgPtr->pgMyPort));
  412.     SetPort(pgPtr->pgOldPort);
  413. }
  414.  
  415.  
  416.  
  417. /**********************************************************
  418.  * EndPatchCode:
  419.  * Dummy proc to mark the end of the code for the patches.
  420.  * Make sure all of your patch code is between here and
  421.  * StartPatchCode.
  422.  **********************************************************/
  423. void EndPatchCode()
  424. {
  425. }